package com.ljy.algorithm;

import java.util.*;

public class Goldstein {
  public static void main(String[]args){
    double[][]f=new double[][]{{1,3},{-2,1},{1,0}};
    int a=0,b=2;
    GsMain gm=new GsMain(f,a,b);
    gm.t=0.618;//可以修改分割比例
    gm.e=0.2;//可以修改精度
    
    double ans=gm.main();//计算，并返回最终结果
    
    gm.visit();//展示计算过程
    
    System.out.println("最终结果："+ans);
  }
}
class GsMain{
  double[][]f;//是个n*2矩阵，每列第一个元素是系数，第二个元素是次方
  final double T=(-1+Math.pow(5,1.0/2))/2;//默认分割比例
  double t;//可以设置比例，例如0.618
  double a,b,a0,b0;//a0,b0记录第i次起始结果，a,b记录变化后的结果
  double fa,fb;//f(a),f(b)
  double e;//精度
  final double E=0.2;//默认精度
  List<String> list=new ArrayList<>();//存储每次运行结果
  public GsMain(double[][]f,double a,double b){
    this.f=f;
    this.t=T;
    this.a=a;
    this.b=b;
    a0=a;
    b0=b;
    e=E;
  }
  
  public double main(){ 
    int count=0;   
    String s=String.format("%4s"+"%6s%6s%6s%6s%14s%6s","次数","a","b","f(a)","f(b)","[a,b]","|b-a|");
    list.add(s);
    while(true){      
      if(++count>20){
        break;
      }
      a=a0+(1-t)*(b0-a0);
      b=a0+t*(b0-a0);
      setFab();//设置f(a)，f(b)
              
      if(fa<=fb){
        //删除右区间
        //以下两行用于记录每轮数据，可忽略
        s=String.format("%4d"+"%6.3f%6.3f%6.3f%6.3f[%6.3f,%6.3f]%6.3f",count,a,b,fa,fb,a0,b,b-a0);      
        list.add(s);
        
        a=a0;//左边界重置
        b0=b;//右边界修改    
      }
      else{
        //删除左区间
        //以下两行用于记录每轮数据，可忽略 
        s=String.format("%4d"+"%6.3f%6.3f%6.3f%6.3f[%6.3f,%6.3f]%6.3f",count,a,b,fa,fb,a,b0,b0-a);
        list.add(s);
        
        b=b0;     
        a0=a; 
      }
      
      if(Math.abs(b-a)<e){
        break ;
      }
    }
    return (a+b)/2;    
  }
  //根据a，b的值设置fa，fb
  void setFab(){
    //系数
    fa=0;
    fb=0;
    for(double[]fi:f){
      //次方 
      fa+=fi[0]*Math.pow(a,fi[1]);
      fb+=fi[0]*Math.pow(b,fi[1]); 
    }
  }
  void visit(){
    for(String s:list){
      System.out.println(s);
    }
  }
  public String toString(){
    StringBuilder sb=new StringBuilder();
    for(String s:list){
      sb.append(s+"\n");
    }
    return sb.toString();
  }
}
